package com.decelo.jpa.service.Impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.decelo.jpa.dao.UserDao;
import com.decelo.jpa.entity.sys.Menu;
import com.decelo.jpa.entity.sys.Role;
import com.decelo.jpa.entity.sys.User;
import com.decelo.jpa.redis.JWTRedisDAO;
import com.decelo.jpa.redis.RedisUtils;
import com.decelo.jpa.result.PageResult;
import com.decelo.jpa.result.Result;
import com.decelo.jpa.result.ResultCode;
import com.decelo.jpa.result.UserToken;
import com.decelo.jpa.service.UserService;
import com.decelo.jpa.utils.EncryptUtils;
import com.decelo.jpa.utils.JWTUtil;
import com.fasterxml.jackson.core.json.UTF8JsonGenerator;
import org.apache.commons.collections.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.util.*;

import static com.alibaba.fastjson.util.IOUtils.UTF8;

@Service
//@CacheConfig(cacheNames={"dev"}) ecache
@Transactional
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;

    @PersistenceContext
    private EntityManager entityManager;

    @Autowired
    private JWTRedisDAO jwtRedisDAO;
    //@Resource
    //private RedisUtils redisUtils;

    @Override
    public List<User> queryAll() {
        return userDao.findAll();
    }

    @Transactional
    @Override
    @CachePut(key="#user")
    public boolean edit(User user) {
        // 生成盐值 加密密码 并持久化管理员信息
        String salt = EncryptUtils.createSalt();
        String newPass = EncryptUtils.encrypt(user.getPossword(), salt);
        String authenticator = EncryptUtils.encrypt(user.getName(), salt);
        user.setPossword(newPass);
        user.setSalt(salt);
        user.setAuthenticator(authenticator);
        User users = userDao.save(user);
        if(users!=null){
            return true;
        }
        return false;
    }

    public boolean saveToken(User user){
         return userDao.save(user)!=null?true:false;
    }

    @Override
    public Page<User> queryParams(PageRequest pageRequest) {
        return userDao.findAll(pageRequest);
    }

    @Override
    public List<User> queryByPersistContext() {
        return userDao.findAll();
    }

    @Override
    //@Cacheable(key ="#name") ecache
    public List<User> queryByName(String name) {
        List<User> users = new ArrayList<>();
        //每次请求值不一致 要改set keyName+参数
        Object cacheValue = jwtRedisDAO.get("queryByName"+(name.length()==0?"":":"+name),Object.class);
        if (cacheValue!=null){
            users= (List<User>)cacheValue;
            return users;
        }
        users=entityManager.createQuery("select t from User t where t.name like:name").setParameter("name", "%"+name+"%").getResultList();
        jwtRedisDAO.set("queryByName"+(name.length()==0?"":":"+name),users);
        return users;
    }

    @Override
    //@Cacheable(key ="#page.pageNo+#page.pageSize+#sql+#countSql") ecache
    //换entityManager跟redis组合
    public PageResult<User> queryByparams(Map<String, Object> params) {
        Integer pageNo = MapUtils.getInteger(params, "pageNo");
        Integer pageSize = MapUtils.getInteger(params, "pageSize");
        PageResult<User> pager= (PageResult<User>) MapUtils.getObject(params,"pager");
        pager.setPageNo(pageNo);
        pager.setPageSize(pageSize);
        //"queryByparams" + "#" + pageNo + "#" + pageSize
        //如何获取请求的方法名
        params.remove("pager");
        Object cacheValue = jwtRedisDAO.get("queryByparams" +jwtRedisDAO.getKeyfromMap(params),PageResult.class);
        if (cacheValue!=null){
            pager= (PageResult<User>) cacheValue;
            return pager;
        }
        String hql="";
        if (!ObjectUtils.isEmpty(params.get("keyword"))){
            hql="select t from User t where t.name like:name";
        }else{
            hql="select t from User t ";
        }
        Query query = entityManager.createQuery(hql);
        if (!ObjectUtils.isEmpty(params.get("keyword"))){
            query.setParameter("name","%"+params.get("keyword")+"%");
        }
        Long totalCount = (long) -1;
        totalCount = (long) query.getResultList().size();
        if (pager != null) { // 分页
            // firstResult的序号从0开始
            query.setFirstResult(pager.getFirst() - 1);
            if (pager.getPageSize() != -1)
                query.setMaxResults(pager.getPageSize());
        }
        pager.setResult(query.getResultList());
        pager.setTotalCount(totalCount);
        jwtRedisDAO.set("queryByparams" +jwtRedisDAO.getKeyfromMap(params),pager);
        return  pager;
    }

    @Override
    public Result getUser(String username,String password) {
        Result result=new Result();
        User user = userDao.getUserByName(username);
        if(null==user){
            result.setCode(ResultCode.NO_FIND_ACCOUNT_ERRO.getCode());
            result.setMsg(ResultCode.NO_FIND_ACCOUNT_ERRO.getMsg());
            return result;
        }
        //判断密码是否正确
        if(!user.getPossword().equals(EncryptUtils.encrypt(password,user.getSalt()))){
            result.setCode(ResultCode.ACCOUNT_PASSWORD_ERRO.getCode());
            result.setMsg(ResultCode.ACCOUNT_PASSWORD_ERRO.getMsg());
            return result;
        }
        //判断是否账号冻结
        /*
        if(user.getStatus()==0){
            result.setCode(ResultCode.ACCOUNT_COLD_ERRO.getCode());
            result.setMsg(ResultCode.ACCOUNT_COLD_ERRO.getMsg());
            return result;
        }
        */
        //生成token
        Map<String,Object> userchaimMap = new HashMap<>();
        userchaimMap.put("userid",user.getId());
        userchaimMap.put("salt",user.getSalt());
        userchaimMap.put("username",user.getName());
        userchaimMap.put("time",System.currentTimeMillis());
        String token ="";
        if (user.getJwttoken()!="" && user.getJwttoken()!=null){
            token=user.getJwttoken();
        }else{
            token = JWTUtil.generateToken(UserToken.Salt, userchaimMap);
            user.setJwttoken(token);
            userchaimMap.put("login",this.saveToken(user));
        }
        //redis持续化
        jwtRedisDAO.set(new String(UserToken.admin+"token").toString(),token);
        /* redisUtils.set(user.getId()+"-token",token);*/
        userchaimMap.put("token",token);
        result.setCode(ResultCode.CODE_200.getCode());
        result.setMsg(ResultCode.CODE_200.getMsg());
        result.setObject(userchaimMap);
        return result;
    }

    @Override
    public User getUserByName(String name) {
        return userDao.getUserByName(name);
    }

    @Override
    public Set<String> queryResourcesByName(String principal) {
        /*User user = this.getUserByName(principal);
        Set<String> menukey=new HashSet<>();
        if (user!=null){
            menukey=userDao.queryMenuKeyById(user.getId());
        }
        return menukey;*/
        return null;
    }

    /**
     * 根据用户名找到对应角色的roleCode
     * @param name
     * @return
     */
    @Override
    public Set<String> findRolesByName(String name){
        return (Set<String>) entityManager.createNativeQuery("select r.r_code from user  u inner join user_role ur on ur.user_id=u.id inner join role r on r.r_id=ur.role_id where u.name=?1").setParameter(1,name).getResultList();
    }

    /**
     * 根据用户名找到对应资源key
     * @param name
     * @return
     */
    @Override
    public Set<String> findMenukeyByName(String name){
        return (Set<String>) entityManager.createNativeQuery("select m.permission_keyValue from menu m inner join role_menu rm on rm.m_id=m.m_id inner join role r on r.r_id=rm.r_id inner join user_role ur on ur.role_id=r.r_id inner join user u on u.id=ur.user_id where u.name=:name").setParameter("name",name).getResultList();
    }
}
